/*
 * Copyright 2025 The JA-SIG Collaborative. All rights reserved. distributed with this file and
 * available online at
 */
package com.lap.auth.application.region.assembler;

import com.github.stuxuhai.jpinyin.PinyinException;
import com.github.stuxuhai.jpinyin.PinyinFormat;
import com.github.stuxuhai.jpinyin.PinyinHelper;
import com.lap.auth.application.region.command.*;
import com.lap.auth.application.region.command.BatchCreateRegionCmd;
import com.lap.auth.application.region.command.BatchUpdateRegionCmd;
import com.lap.auth.application.region.dto.RegionDto;
import com.lap.auth.application.region.dto.RegionOptionDto;
import com.lap.auth.domain.region.Region;
import com.lap.auth.shared.tools.BaseConverter;
import java.util.*;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Mapper(componentModel = "spring")
public interface RegionAssembler extends BaseConverter {
  Logger LOG = LoggerFactory.getLogger(RegionAssembler.class);
  Integer ZERO = 0;

  @Mapping(target = "code", source = "cmd.name", qualifiedByName = "toPinyin")
  Region toDomain(BatchCreateRegionCmd cmd);

  @Mapping(target = "code", source = "cmd.name", qualifiedByName = "toPinyin")
  Region toDomain(Integer id, UpdateRegionCmd cmd);

  @Mapping(target = "code", source = "cmd.name", qualifiedByName = "toPinyin")
  Region toDomain(Integer id, BatchUpdateRegionCmd cmd);

  default List<Region> toChildrenDomains(Region parent, List<UpdateRegionCmd> children) {
    return children.stream()
        .map(
            cmd -> {
              Region child =
                  new Region(
                      cmd.getId(),
                      cmd.getParentId(),
                      toPinyin(cmd.getName()),
                      cmd.getName(),
                      cmd.getSortOrder());
              child.changePidPath(parent.getPidPath(), parent.getId());
              return child;
            })
        .toList();
  }

  @Mapping(target = "pidPaths", source = "pidPath")
  RegionDto toDto(Region region);

  List<RegionDto> toDtoList(List<Region> list);

  RegionOptionDto toOptionDto(Region region);

  List<RegionOptionDto> toOptionDtoList(List<Region> list);

  default List<RegionDto> convertToTree(List<RegionDto> all) {
    List<RegionDto> roots = new ArrayList<>();
    Map<Integer, RegionDto> nodeMap = new HashMap<>();
    for (RegionDto dto : all) {
      dto.setChildren(new ArrayList<>());
      nodeMap.put(dto.getId(), dto);
    }

    for (RegionDto dto : all) {
      if (Objects.equals(dto.getParentId(), ZERO)) {
        roots.add(dto);
      } else {
        RegionDto parent = nodeMap.get(dto.getParentId());
        if (parent != null) {
          parent.getChildren().add(dto);
        }
      }
    }

    for (RegionDto dto : nodeMap.values()) {
      dto.getChildren().sort(Comparator.comparing(RegionDto::getSortOrder));
    }
    roots.sort(Comparator.comparing(RegionDto::getSortOrder));
    return roots;
  }

  @Named("toPinyin")
  default String toPinyin(String name) {
    if (StringUtils.isNotBlank(name)) {
      try {
        return PinyinHelper.convertToPinyinString(name, " ", PinyinFormat.WITHOUT_TONE);
      } catch (PinyinException e) {
        LOG.warn("Pinyin failure,name:{}message:{}", name, e.getLocalizedMessage());
      }
    }
    return "";
  }
}
